/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.netbeans.modules.java; import java.io.*; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import javax.swing.event.ChangeListener; import javax.swing.event.ChangeEvent; import javax.swing.text.BadLocationException; import javax.swing.text.StyledDocument; import org.openide.nodes.*; import org.openide.src.*; import org.openide.cookies.OpenCookie; import org.openide.cookies.ElementCookie; import org.openide.cookies.FilterCookie; import org.openide.filesystems.FileObject; import org.openide.loaders.DataObject; import org.openide.loaders.DataObjectNotFoundException; import org.openide.text.PositionRef; import org.openide.text.PositionBounds; import org.openide.text.EditorSupport; /** Root of the plugable behaviour for the java sources. * * @author Petr Hamernik */ abstract class ElementImpl implements org.openide.src.Element.Impl, ElementProperties, OpenCookie, ElementFactory.Item { /** Element */ transient Element element; /** Property change support */ private transient PropertyChangeSupport support; /** array of cookies for this element */ private transient CookieSet cookieSet; /** Flag that prevents any changes to be made to this element. Any attempt to make such a change will throw SourceException. Currently, elements are locked iff they contain template specification (since Forte do not support them properly) - to prevent source code damage. */ private transient boolean locked; /** True, if the element is not valid - e.g. it was deleted from the source. */ private transient boolean valid = true; /** Reference to TextElement for this source element impl */ Reference textElementRef; /** Position of the begin and the end of the element. */ PositionBounds bounds; /** Bounds of the javadoc. Subclasses may not use it. */ PositionBounds docBounds; /** Bounds of the header. Subclasses may not use it. */ PositionBounds headerBounds; /** Bounds of the body. Subclasses may not use it. */ PositionBounds bodyBounds; /** Javadoc. */ JavaDocImpl javadoc; /** Hash of element's body. Can use any algorithm, must implement equals. Currently, the hash value is computed as CRC-32 of the element's body */ private transient Object bodyHash; static final long serialVersionUID =-1411884372521664497L; /** Default constructor - only for parser. */ ElementImpl() { } /** Constructor */ public ElementImpl(PositionBounds bounds) { this.bounds = bounds; } /** Updates the element fields. This method is called after reparsing. * @param impl the carrier of new information. */ void updateImpl(ElementImpl impl) { bounds = impl.bounds; docBounds = impl.docBounds; headerBounds = impl.headerBounds; bodyBounds = impl.bodyBounds; javadoc = impl.javadoc; javadoc.impl = this; Object newHash; newHash = getBodyHash(); if (newHash != null && (bodyHash == null || !bodyHash.equals(newHash))) { // fire body property change... firePropertyChange(PROP_BODY, null, null); } bodyHash = newHash; } /** Computes and returns CRC32 of element's body @return CRC32 object describing the body */ protected Object getBodyHash() { if (bodyBounds == null) { return null; } if (!bodyBounds.getBegin().getEditorSupport().isDocumentLoaded()) { // Do not even try to compute the hash if the document has not been already // loaded. return null; } java.util.zip.CRC32 crc = null; try { java.util.zip.CRC32 crc2 = new java.util.zip.CRC32(); crc2.update(bodyBounds.getText().getBytes()); crc = crc2; } catch (BadLocationException e) { } catch (IOException e) { } return crc; } void setBodyBounds(PositionBounds b) { bodyBounds = b; bodyHash = getBodyHash(); } /** Get the cookie set. * @return the cookie set. */ protected synchronized final CookieSet getCookieSet() { if (cookieSet == null) { cookieSet = new CookieSet(); cookieSet.add(this); cookieSet.addChangeListener( new ChangeListener() { public void stateChanged(ChangeEvent ev) { ElementImpl.this.firePropertyChange(Node.PROP_COOKIE, null, null); } } ); } return cookieSet; } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); // recompute element's hash according to the document contents. this.bodyHash = getBodyHash(); } /** Get a cookie from the node. * * @param type the representation class * @return the cookie or <code>null</code> */ public Node.Cookie getCookie (Class type) { Node.Cookie c = getCookieSet().getCookie(type); if (c != null) return c; if (ElementCookie.class.isAssignableFrom (type) || FilterCookie.class.isAssignableFrom (type)) return null; if (bounds != null) { EditorSupport ed = bounds.getBegin().getEditorSupport(); if (ed instanceof JavaEditor) { DataObject jdo = ((JavaEditor)ed).getJavaEntry().getDataObject(); c = jdo.getCookie(type); } } return c; } /** Attaches to element */ public void attachedToElement (Element element) { this.element = element; } /** Invokes the open action. */ public void open() { PositionRef begin = (headerBounds != null) ? headerBounds.getBegin() : ((bodyBounds != null) ? bodyBounds.getBegin() : bounds.getBegin()); JavaEditor editor = (JavaEditor) begin.getEditorSupport(); editor.openAt(begin).requestFocus(); } /** Fires property change event. * @param name property name * @param o old value * @param n new value */ protected final void firePropertyChange(String name, Object o, Object n) { if (support != null) { support.firePropertyChange (name, o, n); } } /** Adds property listener */ public synchronized void addPropertyChangeListener (PropertyChangeListener l) { if (support == null) { synchronized (this) { // new test under synchronized block if (support == null) { support = new PropertyChangeSupport (element); } } } support.addPropertyChangeListener (l); } /** Removes property listener */ public void removePropertyChangeListener (PropertyChangeListener l) { if (support != null) { support.removePropertyChangeListener (l); } } abstract SourceElementImpl findSourceElementImpl(); TextElement getTextElement() { TextElement textElement = null; if (textElementRef != null) textElement = (TextElement) textElementRef.get(); if (textElement == null) { textElement = new TextElement(this); textElementRef = new WeakReference(textElement); } return textElement; } public boolean isValid() { return valid; } public void setValid(boolean valid) { this.valid = valid; } public void checkValid() throws SourceException { if (isValid()) { return; } throw new SourceException(Util.getString("EXC_ElementInvalid")); } // ================== Code generation ============================ public boolean isLocked() { return locked; } public void setLocked(boolean enableLock) { locked = enableLock; } public void checkNotLocked() throws SourceException { if (!isLocked()) { checkValid(); return; } throw new SourceException(Util.getString("EXC_ElementLocked")); } boolean isAtOffset(int offset) { if (bodyBounds == null) { return false; } return (bounds.getBegin().getOffset() <= offset) && (bounds.getEnd().getOffset() > offset); } Element findElement(int offset) { return element; } /** Regenerates the javadoc in the source */ /** Returns appropriate position for JavaDoc comment for the element. @return Position where the comment should start. If the element already has a comment, returns position of the comment's beginning. */ PositionRef getJavaDocPosition() { if (docBounds != null) { return docBounds.getBegin(); } else { return bounds.getBegin(); } } void removeFromSource() throws SourceException { checkValid(); SourceElementImpl.clearBounds(bounds); } void regenerateJavaDoc() throws SourceException { checkValid(); CodeGenerator.regenerateJavaDoc(element, this); } /** Regenerates the header in the source */ void regenerateHeader() throws SourceException { checkNotLocked(); CodeGenerator.regenerateHeader(element, this); } /** Regenerates the whole element in the source. * Also updates the bounds of javadoc, header and body */ void regenerate(Element element) throws SourceException { checkNotLocked(); CodeGenerator.regenerateElement(element, this); } /** Creates the bounds for new element. The element type (class, * method, ...) is given by the instance of the collection. * @param col The calling collection * @exception SourceException this implementation always throws * (must be rewriten in ClassElementImpl and SourceElementImpl) */ PositionBounds createBoundsFor(ElementsCollection col) throws SourceException { throw new SourceException(); } } /* * Log * 28 Gandalf-post-FCS1.21.2.5 4/6/00 Svatopluk Dedic Extended messages for * SourceExceptions * 27 Gandalf-post-FCS1.21.2.4 3/30/00 Svatopluk Dedic Hash is computed only if * document has been loaded * 26 Gandalf-post-FCS1.21.2.3 3/27/00 Svatopluk Dedic Fix for serialization * problems with CRC32 * 25 Gandalf-post-FCS1.21.2.2 3/8/00 Svatopluk Dedic Invalid elements do not * allow modifications. * 24 Gandalf-post-FCS1.21.2.1 2/24/00 Svatopluk Dedic Minor changes * 23 Gandalf-post-FCS1.21.2.0 2/24/00 Ian Formanek Post FCS changes * 22 src-jtulach1.21 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems copyright in file comment * 21 src-jtulach1.20 9/13/99 Petr Hamernik minor changes * 20 src-jtulach1.19 8/9/99 Ian Formanek Generated Serial Version * UID * 19 src-jtulach1.18 7/8/99 Petr Hamernik changes reflecting * org.openide.src changes * 18 src-jtulach1.17 7/3/99 Petr Hamernik SourceCookie.Editor - * 1st version * 17 src-jtulach1.16 6/9/99 Ian Formanek ---- Package Change To * org.openide ---- * 16 src-jtulach1.15 6/2/99 Petr Hamernik connections of java * sources * 15 src-jtulach1.14 5/24/99 Petr Hamernik javadocimpl bugfix * 14 src-jtulach1.13 5/13/99 Jan Jancura Do not delegate Element * & Filter Cookies * 13 src-jtulach1.12 5/10/99 Petr Hamernik * 12 src-jtulach1.11 4/30/99 Petr Hamernik * 11 src-jtulach1.10 4/21/99 Petr Hamernik Java module updated * 10 src-jtulach1.9 4/7/99 Petr Hamernik * 9 src-jtulach1.8 3/29/99 Petr Hamernik * 8 src-jtulach1.7 3/29/99 Petr Hamernik * 7 src-jtulach1.6 3/29/99 Ian Formanek removed import of * modules.compiler * 6 src-jtulach1.5 3/18/99 Petr Hamernik * 5 src-jtulach1.4 3/18/99 Petr Hamernik * 4 src-jtulach1.3 3/10/99 Petr Hamernik * 3 src-jtulach1.2 2/25/99 Petr Hamernik * 2 src-jtulach1.1 2/17/99 Petr Hamernik * 1 src-jtulach1.0 2/11/99 Petr Hamernik * $ */